#include <string.h>
#include <stdlib.h>
#include "demo1.h"
#include <dlfcn.h>
#include "example.h"
#include <pthread.h>
#include <time.h>

typedef struct Node Node;
/*
 * 结构体-- 学生
 *
 */
struct Stu
{
    char name[20];
    short age;

};

/**
 * 传对象
 * @param s
 */
void Print1(struct Stu s)
{
    printf("sizeof(s) = %d \n",sizeof(s));
    printf("Print1 Stu s.name = %s, s.age = %d \n" ,s.name,s.age);
}

/**
 * 传指针地址
 * @param s
 */
void Print2(struct Stu *s)
{
    printf("sizeof(s) = %d \n",sizeof(s));
    printf("Print1 Stu s->name = %s, s->age = %d \n" ,s->name,s->age);
}

// 函数，使用一级指针参数
void updateInfo(struct Stu *infoCopy, const char *newName) {
    // 这个函数只能修改 infoCopy 的副本，不能修改原始的 info
    strcpy(infoCopy->name, newName);

    // 将一级指针置空，但是不会影响到原地址的输出
    infoCopy = NULL;

    printf("infoCopy->name = %s \n",infoCopy->name);
}

// 函数，使用二级指针参数
void updateInfoWithPointerToPointer(struct Stu **infoPtr, const char *newName) {
    // 这个函数可以直接修改原始的 info
    strcpy((*infoPtr)->name, newName);

    printf("infoPtr->name = %s \n",(*infoPtr)->name);
}

int SumOfElements(int A[])
{
    int sum = 0;
    
    int size = sizeof(A)/ sizeof(A[0]);

    printf("sizeOf(A) = %d\n", sizeof(A));
    printf("sizeOf(A[0]) = %d\n", sizeof(A[0]));

    for (int i = 0; i < size; i++) {

        sum += A[i];
    }

    printf("sum = %d\n", sum);

    return sum;
}

int testArr(int *arr, int size)
{
    for (int i = 0; i < size; i++) {

        printf("arr[%d] = %d ",i,arr[i]);
    }

    printf("\n");
}

void print(char *C)
{

    while (*C != '\0')
    {
        printf("%c ",*C);
        C++;
    }
    printf("\n");
}

// 初始化头指针为 NULL
Node* head = NULL;

void Insert(int x);

void InsertNodeEnd(int x);

void PrintNode();

#define MALLOC(num,type) (void*)malloc(num * sizeof(type))
#define __DEBUG__ 1
#define __DEBUG2__

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* thread_function(void* arg) {

    int num = *((int*)arg);  // 将传入的指针转换为整数

    time_t current_time;
    struct tm* time_info;

    // 获取当前时间
    time(&current_time);
    // 将当前时间转换为本地时间
    time_info = localtime(&current_time);

    pthread_mutex_lock(&mutex);  // 加锁
    printf("Hello from thread!\n");
    printf("Thread is in the critical section.\n");
    pthread_mutex_unlock(&mutex);  // 解锁

    // 打印当前时间（格式：YYYY-MM-DD HH:MM:SS）
    printf("Thread Time: %04d-%02d-%02d %02d:%02d:%02d\n",
           time_info->tm_year + 1900,  // tm_year 是从1900年开始的，所以加上1900
           time_info->tm_mon + 1,      // tm_mon 是从0开始的，所以加上1
           time_info->tm_mday,
           time_info->tm_hour,
           time_info->tm_min,
           time_info->tm_sec);
    return NULL;
}

/**
 * 使用pthread创建一个线程
 */
void testPthread()
{

     int lf = 40;
    pthread_t thread_id1,thread_id2;

    /**
     * 参数：
     * pthread_create 函数用来创建一个新线程，其参数包括：
        thread：线程 ID
        attr：线程属性，通常为 NULL 使用默认值
        start_routine：线程执行的启动函数
        arg：传递给启动函数的参数

        返回值：
        pthread_create 返回一个整数值，表示函数调用是否成功。如果返回值是 0，表示线程创建成功；如果返回值是一个错误代码，则表示线程创建失败。

        常见的返回值包括：
            0：成功创建线程
            EAGAIN：系统资源不足，无法创建线程
            EINVAL：给定的属性无效
            EPERM：没有权限创建线程（通常发生在某些特权操作系统中）
     */
    // 创建线程，调用 thread_function
    pthread_create(&thread_id1, NULL, thread_function, &lf);
    pthread_create(&thread_id2, NULL, thread_function, &lf);

    // 等待线程结束
    pthread_join(thread_id1, NULL);
    pthread_join(thread_id2, NULL);
}

int main() {

    testPthread();

    print1204(9);

    printf("\n");


    int* int_1 = (int*)MALLOC(5,int);
    printf("sizeof(int_1) : %d \n", sizeof(int_1));

#ifdef __DEBUG2__
    printf("hello3 !");
#endif

#ifndef __DEBUG2__
    printf("hello3_1 !");
#endif

#if __DEBUG__
    printf("hello !");
#endif

#if 1
    printf("hh");
#endif
#if 0
    printf("hh1");
#endif
    // ---------------

    // 操作目录及文件
    // test01();

    FILE *file = fopen("/Users/cls/Documents/ClionPosition/demo_c/day1201/example.txt", "r+");  // "w" 模式表示写入文件，如果文件不存在会创建
    if (file == NULL) {
        printf("Unable to open or create file.\n");
        return 1;  // 打开文件失败
    }

    // 使用 fprintf 向文件写入格式化内容
    fprintf(file, "Hello, world!\n");
    fprintf(file, "This is a number: %d\n", 42);
    fprintf(file, "This is a floating-point number: %.2f\n", 3.14159);
    fprintf(file, "Hello, this is a test file!\n");  // 向文件写入数据
    fputs ("fopen example\n",file);

    // 向文件中写入单个字符
    fputc('H', file);  // 写入字符 'H'
    fputc('e', file);  // 写入字符 'e'
    fputc('l', file);  // 写入字符 'l'
    fputc('l', file);  // 写入字符 'l'
    fputc('o', file);  // 写入字符 'o'
    fputc(' ', file);  // 写入空格
    fputc('W', file);  // 写入字符 'W'
    fputc('o', file);  // 写入字符 'o'
    fputc('r', file);  // 写入字符 'r'
    fputc('l', file);  // 写入字符 'l'
    fputc('d', file);  // 写入字符 'd'
    fputc('!', file);  // 写入字符 '!'

//    printf("从example.txt 文件中读取内容为: \n");
//
//    int ch;  // 用于存储读取的字符
//    while ((ch = fgetc(file)) != EOF) {  // 循环读取文件中的字符，直到遇到 EOF
//        printf("%c", ch);  // 使用 printf 输出字符
//    }
//
//    printf("\n");

    fprintf(file, "\n");
    fprintf(file, "Hello, world1!\n");

    fprintf(file, "Hello, world3!\n");



//    if (feof(file)) {
//        printf("已达到文件结尾!\n");
//    } else if (ferror(file)) {
//        perror("读取文件时发生错误!");
//    }

//    int result = fprintf(file, "Hello, world3!\n");
//    if (result < 0) {
//        perror("写入文件失败");
//        fclose(file);
//        return 1;
//    }
//    else
//    {
//        printf("fprintf 写入文件内容成功!");
//    }

    printf("\n");

    fputc('H', file);  // 写入字符 'H'
    fputc('e', file);  // 写入字符 'e'
    fputc('l', file);  // 写入字符 'l'
    fputc('l', file);  // 写入字符 'l'
    fputc('o', file);  // 写入字符 'o'

    int ch;

    ch = fgetc(file);

    printf("%d",ch);
//    while ((ch = fgetc(file)) != EOF) {
//        printf("%c",ch);  // 输出每个字符
//    }
    if (ch == EOF) {
        if (feof(file)) {
            printf("文件已读完\n");
        } else if (ferror(file)) {
            printf("读取文件时发生错误\n");
        }
    } else {
        printf("读取的字符的 ASCII 值: %d\n", ch);  // 输出读取字符的 ASCII 值
    }

    long file_size = ftell(file);  // 获取文件大小
    printf("文件大小: %ld bytes\n", file_size);

    fclose(file);  // 关闭文件


    // ----------------------

    // ---- 加载动态so库文件
    /**
     *  void* dlopen(const char* filename, int flag);
        filename：要加载的共享库的路径（可以是绝对路径或相对路径）。如果值为 NULL，表示加载主程序（通常不使用该选项）。
        flag：用于指定加载共享库的方式，可以是以下的一个或多个标志的组合：
        RTLD_LAZY：延迟加载，即只有在调用符号时才进行解析。
        RTLD_NOW：立即加载，即在加载时解析所有符号。
        RTLD_GLOBAL：使库中的符号在其他共享库中可见（默认是 RTLD_LOCAL，即符号仅在当前库内部可见）。
        RTLD_LOCAL：符号只对当前共享库可见。
     */
    void* handle = dlopen("/Users/cls/Documents/ClionPosition/demo_c/libexample.so", RTLD_LAZY);
    /**
     * 返回值：
        成功时，dlopen 返回一个非 NULL 的指针，指向已加载的共享库的句柄。
        失败时，返回 NULL，并且可以使用 dlerror() 函数获取错误信息。
     */
    if (!handle)
    {
        // 如果加载失败，输出错误信息
        fprintf(stderr, "Error loading library: %s\n", dlerror());
    }
    else
    {
        printf("libexample.so 库已经被成功加载!\n");
    }

    // 获取库中的函数
    void (*hello)();
    void (*test)(int);

    // dlsym()：用于查找共享库中某个符号（函数或变量）。
    // 它返回一个指向该符号的指针，可以将其转换为合适的函数指针类型。
    hello = dlsym(handle,"hello");
    test = dlsym(handle,"test");

    // 检查函数是否找到
    if (!hello)
    {
        fprintf(stderr, "Error finding symbol: %s\n", dlerror());
        dlclose(handle);
    }

    // 调用函数
    hello();
    test(10);

    // 关闭已加载的共享库，释放资源。
    dlclose(handle);

    // ---------------------


    const int mml = 39;
    const int mml1 = 39;

    int* const lh = &mml;
    const int* lh1 = &mml;

    printf("*lh = %d \n",*lh);

//    *lh = 64;
//    *lh1 = 64;
//    lh = &mml1;
//    lh1 = &mml1;

    // -----------------
    // int *r = (int*)malloc(3 * sizeof(int));
    int *ml = (int*)calloc(3, sizeof(int));
    printf("Calloc ml Address %p \n",ml);

    for (int i = 0; i < 3; i++) {

        ml[i] = 6;
        printf("ml[%d] is %d " ,i,ml[i]);
        printf(" Address is %p " ,ml+i);
    }

    printf("\n");

    // ------------------

    int arr64[3][5] = {{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}};

    print2(&arr64,3,5);

    print3(&arr64,3,5);

    // --------------

    demo1107();

    demo1108();

    demo1109();

    // ---------

    int f = 2015;
    int *p = &f;
    printf("size of integer is %d bytes\n",sizeof(int));
    printf("f Address = %p, value is %d\n",&f,f);
    printf("p Address = %p, value is %d\n",p,*p);
    printf("p+1 Address = %p, value is %d\n",p+1,*(p+1));

    void *p0;

    printf("pointer void *p0 sizeof is = %d\n", sizeof(p0));
    p0 = p;  // 将 int *p 转换为 void *
    printf("Address = %p\n",p0);

    // 想从 void * 恢复到原始指针类型，必须进行强转。
    printf("Value = %d\n", *(int *)p0); // 恢复为 int * 以访问值

    printf("pointer int *p sizeof is = %d\n", sizeof(p));
    printf("pointer void *p0 sizeof is = %d\n", sizeof(p0));
//    ------------

    int B[5] = {1,2,3,4,5};

    printf("sizeOf(B) = %d\n", sizeof(B));
    printf("sizeOf(B[0]) = %d\n", sizeof(B[0]));

    int size1 = sizeof(B)/sizeof(B[0]);

    int sum = 0;
    int *q = B;

    for (int i = 0; i < size1; i++) {

        printf("B[%d] = %d\n",i,q[i]);

        sum += q[i];

    }
    

     printf("sum = %d\n",sum);

    // --------

    testArr(B,size1);

    printf("Modified array: ");
    for (int i = 0; i < size1; i++) {
        printf("%d ", B[i]);
    }
    printf("\n");

//    ------------

    char a = -1;
    signed char b = -1;
    unsigned char c = -1;

    printf(" a = %d,b = %d,c = %d \n",a,b,c);

    // ----------------

    // How to store strings
    // size of array >= no.of characters in string + 1
    char ch8[8];

    ch8[0] = 'H';
    ch8[1] = 'e';
    ch8[2] = 'l';
    ch8[3] = 'l';

    printf("ch8 = %s \n",ch8);
    printf("str len (ch8) = %d \n",strlen(ch8));

    print(&ch8);

    // ----------

    int *r = (int*)malloc(3 * sizeof(int));

    *r = 10;
    *(r+2) = 16;

    printf("r = %d \n", *r);
    printf("(r+2) = %d \n", *(r+2));

    free(r);

    printf("free(r) later r = %d \n", *r);

    // ----------

    void (*ptr)();
    ptr = PrintHello;
    ptr("Wyd And Cls");

    process(5,7,Add);

    // ----------

//    printf("head Address is %p \n",head);
//    printf("How many numbers? \n");
//
//    int n,x;
//    scanf("%d",&n);
//    for (int i = 0; i < n; i++)
//    {
//        printf("Enter the number \n");
//        scanf("%d",&x);
//        Insert(x);
//        PrintNode();
//    }

//    struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
//    temp->data = 2;
//    printf("temp.data is %d ,temp Address is %p \n",temp->data,temp);

    //new N1



   // A = temp;

    //printf("A.data is %d ,A Address is %p \n",A->data,A);

    // ----------


    int m = 10,o=19,l=20,k=2;
    int* parr[4]; // 存放整形指针的数组,指针数组

    parr[0] = &m;
    parr[1] = &o;
    parr[2] = &l;
    parr[3] = &k;

    int len = sizeof(parr)/sizeof(parr[0]);
    printf("len = %d \n",len);

    for (int i = 0; i < len; ++i) {

        printf("parr[%d]= %d\n",i,*parr[i]);
        printf("parr[%d]= %d\n",i,parr[i]);
    }

    int* p4 = NULL;
    printf("指针p4的地址为:%p \n",p4);

    p4 = &m;
    printf("指针p4的地址为:%p p4指向的值:%d\n",p4,*p4);


    printf("Hello, World!\n");

    //
    struct Stu stu = {"hello",20};

    printf("stu.name = %s \n",stu.name);

    Print1(stu);
    Print2(&stu);

    struct Stu *infoPtr = &stu;

    // 尝试使用一级指针参数更新信息
    updateInfo(infoPtr, "Jane Doe");

    printf("stu.name = %s \n",stu.name);

    updateInfoWithPointerToPointer(&infoPtr,"www");

    printf("stu.name = %s \n",stu.name);
    return 0;
}

void PrintNode()
{

    Node* temp = head;

    printf("List is:  ");

    while (temp != NULL )
    {
        printf("%d ",temp->data);
        temp = temp->next;
    }
    printf("\n");
}

/**
 * 在链表开头插入
 * @param x
 */
void Insert(int x)
{

    // 申请一个内存空间
    Node* temp = (Node*)malloc(sizeof(Node));

    if (!temp) {
        printf("Memory allocation failed\n");
        return;
    }
    printf("temp Address is %p",temp);

    temp->data = x;
    temp->next = head; // 新节点指向当前的头节点
    head = temp;  // 更新头指针
    printf("temp.data is %d",temp->data);
    printf("head.data is %d \n",head->data);
}


void InsertNodeEnd(int x)
{
    // 申请一个内存空间
    struct Node* temp = (struct Node*)malloc(sizeof(struct Node));
    if (!temp) {
        printf("Memory allocation failed\n");
        return;
    }

    temp->data = x;
    temp->next = NULL;

    if (head == NULL)
    {
        head = temp; // 如果链表为空，新节点成为头节点
    } else
    {
        Node* current = head;

        // 找到最好一个节点
        while (current->next != NULL)
        {
            current = current->next;  // 找到链表的最后一个节点
        }
        current->next = temp;  // 将新节点添加到最后
    }



}